﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Globalization;

namespace BingDownloader
{
    public class BingObject
    {
        private string _countryName;
        private string _downloadURL;
        private string _bingImageURL;
        private List<string> _hotURLs;
        private List<string> _hotDescriptions;
        private string _imageName;
        private Bitmap _bingImage;

        public BingObject(string countryName, string downloadURL)
        {
            _countryName = countryName;
            _downloadURL = downloadURL;

            _hotURLs = new List<string>();
            _hotDescriptions = new List<string>();            
        }

        public string ImageName
        {
            get { return _imageName; }
            set { _imageName = value; }
        }

        public string CountryName
        {
            get { return _countryName; }            
        }

        public string DownloadURL
        {
            get { return _downloadURL; }            
        }

        public Bitmap Image
        {
            get { return _bingImage; }
            set { _bingImage = value; }
        }

        public string ImageURL
        {
            get { return _bingImageURL; }
            set { _bingImageURL = value; }
        }

        public string CountryCode
        {
            get 
            {
                return _downloadURL.Substring(_downloadURL.Length - 2, 2).ToUpper();
            }
        }

        public void GetBingImageFileAndHotHits()
        {
            List<string> returnStrings = new List<string>();
            string fullWebpageText = BingHelper.RetrieveWebPageAsString(_downloadURL);
            string findStr = "g_img={url:'";
            int startIndex = fullWebpageText.IndexOf(findStr);
            startIndex += findStr.Length;
            int lastIndex = fullWebpageText.IndexOf('\'', startIndex);

            string imgPath = fullWebpageText.Substring(startIndex, lastIndex - startIndex);
            imgPath = imgPath.Replace(@"\", "");

            _bingImageURL = (BingHelper.bing + imgPath);

            // find the image name
            string findImageNameStr = "&copy;</div><span>";
            startIndex = fullWebpageText.IndexOf(findImageNameStr);
            startIndex += findImageNameStr.Length;
            lastIndex = fullWebpageText.IndexOf("</span>", startIndex);

            _imageName = fullWebpageText.Substring(startIndex, lastIndex - startIndex);
            // find the image name ends

            try
            {
                string findHotNameStr = "g_hot=";
                startIndex = fullWebpageText.IndexOf(findHotNameStr);
                startIndex += findHotNameStr.Length;
                lastIndex = fullWebpageText.IndexOf("}};;", startIndex);

                string hotText = fullWebpageText.Substring(startIndex, lastIndex - startIndex);

                string[] seperators = { @"}" };
                string[] splittedHotText = hotText.Split(seperators, StringSplitOptions.RemoveEmptyEntries);

                foreach (string tempHotText in splittedHotText)
                {
                    // extract all text from 7th char to the last but 2 chars                
                    string hotTextFinal = tempHotText.Substring(7, tempHotText.Length - 7 - 2 + 1);
                    int indexToBeRemoved = hotTextFinal.IndexOf(",1:");
                    hotTextFinal = hotTextFinal.Remove(indexToBeRemoved, 3);                    
                    hotTextFinal = hotTextFinal.Replace("\'", "");
                    _hotDescriptions.Add(hotTextFinal);
                }

                string hotURLStartString = "<a href=\"";
                for (int i = 1; i < 5; i++)
                {
                    string hotURLEndString = ";form=hphot" + i.ToString();
                    lastIndex = fullWebpageText.IndexOf(hotURLEndString);
                    lastIndex += hotURLEndString.Length;
                    startIndex = fullWebpageText.LastIndexOf(hotURLStartString, lastIndex);
                    startIndex += hotURLStartString.Length;
                    _hotURLs.Add(fullWebpageText.Substring(startIndex, lastIndex - startIndex));
                }
            }
            catch (ArgumentOutOfRangeException)
            {
                //ignore argument out of range exception
                // not all bing websites have hot texts...
            }
            // links start with <a href and ends with class="sh_hs"


        }

        public void DownloadImage()
        {
            _bingImage = BingHelper.RetriveBitmapAtLocation(_bingImageURL);
        }

        internal string GetHotLinkDescription(int p)
        {
            if (_hotDescriptions.Count < p) return null;
            return _hotDescriptions[p-1];
        }

        internal string GetHotLinkURL(int p)
        {
            if (_hotURLs.Count < p) return null;
            return _hotURLs[p-1];
        }
    }

    static class BingHelper
    {
        public static int BingImagesCount
        {
            get { return bingObjects.Count; }
        }
        
        public delegate void BingObjectFoundDelegate(BingObject bo);
        public static BingObjectFoundDelegate ObjectFound;

        static Thread bingFileURLGetterThread;
        //static Thread bingImageGetterThread;
        static bool stopRequested = false;
        static List<BingObject> bingObjects = new List<BingObject>();

        internal static string bing = "http://www.bing.com/";
        
        
        static BingHelper()
        {
            bingObjects.Add(new BingObject("United States", "http://www.bing.com/?mkt=en-US"));
            bingObjects.Add(new BingObject("Singapore (International)", "http://www.bing.com.sg"));
            bingObjects.Add(new BingObject("Japan (日本)", "http://www.bing.co.jp"));
            bingObjects.Add(new BingObject("United Kingdom", "http://www.bing.co.uk"));
            bingObjects.Add(new BingObject("Canada", "http://www.bing.com/?mkt=en-CA"));
            bingObjects.Add(new BingObject("China (中国)", "http://www.bing.com.cn"));
            bingObjects.Add(new BingObject("Germany (Deutschland)", "http://www.bing.com/?cc=de"));
        }        
                
        // downloads the html of the passed 
        internal static string RetrieveWebPageAsString(string query)
        {
            // prepare the web page we will be asking for
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(query);
            request.Proxy = WebRequest.GetSystemWebProxy();
            request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
            // execute the request
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse) request.GetResponse();
            }
            catch (Exception /*e*/)
            {                
                throw new ApplicationException("Internet Access is not available or your computer is behind a firewall!");
            }
           
            string fileContent = string.Empty;
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                fileContent = sr.ReadToEnd();
            }

            return fileContent;            
        }

        internal static Bitmap RetriveBitmapAtLocation(string query)
        {
            // prepare the web page we will be asking for
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(query);
            request.Proxy = WebRequest.GetSystemWebProxy();
            request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
            // execute the request
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)
                request.GetResponse();
            }
            catch (Exception /*e*/)
            {
                throw new ApplicationException("Internet Access is not available or your computer is behind a firewall!");                
            }

            return new Bitmap(response.GetResponseStream());            
        }

        public static void StopGettingBingImages()
        {
            stopRequested = true;
        }

        public static void BeginGettingBingImages()
        {
            bingFileURLGetterThread = new Thread(new ThreadStart(GetBingImageURLs));
            bingFileURLGetterThread.Start();
        }

        private static void GetBingImageURLs()
        {
            List<string> bingImageURLs = new List<string>();            
            foreach (BingObject bo in bingObjects)
            {
                bo.GetBingImageFileAndHotHits();                                                

                if (stopRequested) return;                

                Thread bingImageGetterThread = new Thread(new ParameterizedThreadStart(GetBingImage));
                bingImageGetterThread.Start(bo);
            }
        }

        private static void GetBingImage(object objParameter)
        {
            BingObject bo = objParameter as BingObject;
            bo.DownloadImage();            
            if (stopRequested) return;
            ObjectFound(bo);          
        }

        public static BingObject GetBingObject(int p)
        {
            return bingObjects[p];
        }
    }
}